package com.minimalist.common.feign.monitor;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Feign降级监控
 *
 * @author 11987
 */
@Component
public class FeignDegradeMonitor {
    private static final Logger log = LoggerFactory.getLogger(FeignDegradeMonitor.class);

    // 服务降级统计
    private final Map<String, ServiceDegradeStats> statsMap = new ConcurrentHashMap<>();

    /**
     * 记录服务降级
     */
    public void recordDegrade(String serviceName) {
        recordDegrade(serviceName, "未知原因");
    }

    /**
     * 记录服务降级，包含异常原因
     */
    public void recordDegrade(String serviceName, String causeMessage) {
        ServiceDegradeStats stats = statsMap.computeIfAbsent(serviceName,
                k -> new ServiceDegradeStats(serviceName));
        stats.incrementCount();
        stats.addCause(causeMessage);
    }

    /**
     * 定时输出降级统计报告
     */
    @Scheduled(fixedRate = 300000) // 5分钟
    public void reportDegradeStats() {
        if (statsMap.isEmpty()) {
            return;
        }

        List<ServiceDegradeStats> statsList = new ArrayList<>(statsMap.values());
        statsList.sort((a, b) -> b.getCount().get() - a.getCount().get());

        // 格式化当前时间
        String currentTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

        StringBuilder report = new StringBuilder("=== Feign服务降级统计报告 ===\n");
        report.append("统计时间: ").append(currentTime).append("\n");
        report.append("时间范围: 最近5分钟\n");
        report.append("总降级服务数: ").append(statsList.size()).append("\n");
        report.append("详细统计:\n");

        for (ServiceDegradeStats stats : statsList) {
            // 格式化首次发生时间
            String firstOccurTime = LocalDateTime.ofInstant(
                            Instant.ofEpochMilli(stats.getFirstOccurTime()),
                            ZoneId.systemDefault())
                    .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

            report.append("- 服务: ").append(stats.getServiceName())
                    .append(", 降级次数: ").append(stats.getCount().get())
                    .append(", 首次发生: ").append(firstOccurTime)
                    .append("\n");

            // 添加异常原因统计
            Map<String, AtomicInteger> causeCounts = stats.getCauseCounts();
            if (!causeCounts.isEmpty()) {
                report.append("  异常原因统计:\n");
                causeCounts.forEach((cause, count) -> report.append("    - ").append(cause)
                        .append(": ").append(count.get())
                        .append("\n"));
            }
        }

        log.warn(report.toString());

        // 重置统计
        statsMap.clear();
    }

    static class ServiceDegradeStats {
        private final String serviceName;
        private final AtomicInteger count = new AtomicInteger(0);
        private final long firstOccurTime = System.currentTimeMillis();
        private final Map<String, AtomicInteger> causeCounts = new ConcurrentHashMap<>();

        public ServiceDegradeStats(String serviceName) {
            this.serviceName = serviceName;
        }

        public void incrementCount() {
            count.incrementAndGet();
        }

        public void addCause(String causeMessage) {
            if (causeMessage != null) {
                causeCounts.computeIfAbsent(causeMessage, k -> new AtomicInteger(0))
                        .incrementAndGet();
            }
        }

        /**
         * 获取格式化后的首次发生时间
         */
        public String getServiceName() {
            return serviceName;
        }

        public AtomicInteger getCount() {
            return count;
        }

        public long getFirstOccurTime() {
            return firstOccurTime;
        }

        public Map<String, AtomicInteger> getCauseCounts() {
            return causeCounts;
        }

        /**
         * 获取格式化后的首次发生时间
         */
        public String getFormattedFirstOccurTime() {
            return LocalDateTime.ofInstant(
                            Instant.ofEpochMilli(firstOccurTime),
                            ZoneId.systemDefault())
                    .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        }
    }
}
